#include "FeatureExtractor.h"
#include <iostream>
#include <cmath>

std::vector<double> extractHuMoments(const cv::Mat& image) {
    // 转换为灰度图像
    cv::Mat grayImg;
    cv::cvtColor(image, grayImg, cv::COLOR_BGR2GRAY);
 
    // 计算Hu矩
    cv::Moments moments = cv::moments(grayImg);
    cv::Mat hu;
    cv::HuMoments(moments, hu);
 
    // 处理Hu矩数值
    std::vector<double> processedHuMoments;
    for (int i = 0; i < 7; ++i) {
        double val = hu.at<double>(i);
        processedHuMoments.push_back(
            std::copysign(1.0, val) * std::log10(std::abs(val) + 1e-10)
        );
    }
 
    return processedHuMoments;
}

GeometricFeatures extractGeometricFeatures(const cv::Mat& image) {
    cv::Mat grayImg;
    // 转换为灰度图
    if (image.channels() == 3) {
        cv::cvtColor(image, grayImg, cv::COLOR_BGR2GRAY);
    } else {
        grayImg = image.clone();
    }
    // 高斯模糊去噪
    cv::GaussianBlur(grayImg, grayImg, cv::Size(5,5), 0);
    // 自适应二值化（Otsu）
    cv::threshold(grayImg, grayImg, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    // 形态学闭合填充缺口
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5,5));
    cv::morphologyEx(grayImg, grayImg, cv::MORPH_CLOSE, kernel);
    // 提取轮廓
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(grayImg, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    GeometricFeatures features = {0.0, 0.0, 0.0};
    if (!contours.empty()) {
        // 按面积排序，选择最大轮廓
        std::sort(contours.begin(), contours.end(),
            [](const std::vector<cv::Point>& a, const std::vector<cv::Point>& b) {
                return cv::contourArea(a) > cv::contourArea(b);
            });
        const auto& largestContour = contours[0];
        
        // 计算几何特征
        features.area = cv::contourArea(largestContour);
        features.perimeter = cv::arcLength(largestContour, true);
        // 计算最小外接矩形宽高比
        cv::RotatedRect rect = cv::minAreaRect(largestContour);
        features.aspectRatio = (rect.size.width > rect.size.height) ?
            rect.size.width / rect.size.height : 
            rect.size.height / rect.size.width; // 确保 >=1
    } else {
        std::cerr << "警告：未检测到轮廓，请检查输入图像！" << std::endl;
    } 
    return features;
}

std::vector<double> extractProjectionHistogram(const cv::Mat& image) {
    if (image.empty()) {
        throw std::invalid_argument("Input image is empty");
    }
    // 转换为灰度图
    cv::Mat grayImg;
    if (image.channels() == 3) {
        cv::cvtColor(image, grayImg, cv::COLOR_BGR2GRAY);
    } else {
        grayImg = image.clone();
    }
    // 图像尺寸标准化：固定宽度为64像素，高度按比例缩放
    int target_width = 64;
    cv::resize(grayImg, grayImg, cv::Size(target_width, grayImg.rows));
    // 自适应二值化（Otsu算法）
    cv::threshold(grayImg, grayImg, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    // 垂直投影（沿列方向求和）
    cv::Mat proj;
    cv::reduce(grayImg, proj, 0, cv::REDUCE_SUM, CV_64F);
    // 转换为向量并归一化
    std::vector<double> histogram;
    proj.convertTo(histogram, CV_64F);
    double max_val = grayImg.rows * 255.0; // 最大可能值
    for (auto& val : histogram) {
        val /= max_val; // 归一化到 [0,1]
    }
    return histogram; // 长度固定为 target_width（64）
}

// 提取区域密度特征函数
std::array<double, 5> extractZoneDensity(const cv::Mat& image) {
    cv::Mat grayImg;
    cv::cvtColor(image, grayImg, cv::COLOR_BGR2GRAY);
    cv::threshold(grayImg, grayImg, 128, 255, cv::THRESH_BINARY);

    const int h = grayImg.rows;
    const int w = grayImg.cols;
    
    // 定义5个关键区域
    cv::Rect zones[5] = {
        cv::Rect(0, 0, w, h/3),         // 顶部区域
        cv::Rect(w/3, h/3, w/3, h/3),   // 中心区域
        cv::Rect(0, 2*h/3, w, h/3),     // 底部区域
        cv::Rect(0, 0, w/3, h),         // 左侧区域
        cv::Rect(2*w/3, 0, w/3, h)      // 右侧区域
    };

    std::array<double, 5> densities;
    for (int i = 0; i < 5; ++i) {
        cv::Mat roi = grayImg(zones[i]);
        densities[i] = cv::countNonZero(roi) / (double)roi.total();
    }
    return densities;
}

std::string extractcolor(const cv::Mat& image)
{
	
   // cv::imshow("Image Display", img);
    //cv::waitKey(0);

    // 转换为 HSV 空间
    cv::Mat hsvImg;
    cv::cvtColor(image, hsvImg, cv::COLOR_BGR2HSV);

    // 判断颜色（红色或黑色）
    const int minSaturation = 40;  // 最小饱和度阈值
    const int minValue = 30;       // 最小亮度阈值
    const float redThreshold = 0.3; // 红色像素比例阈值

    int redCount = 0;
    int validPixels = 0;

    // 遍历所有像素
    for (int i = 0; i < hsvImg.rows; ++i) {
        for (int j = 0; j < hsvImg.cols; ++j) {
            cv::Vec3b hsv = hsvImg.at<cv::Vec3b>(i, j);

            // 过滤无效像素（低饱和度或低亮度）
            if (hsv[1] > minSaturation && hsv[2] > minValue) {
               ++validPixels;

                // Hue值范围处理（OpenCV将Hue缩放到0-180）
                if ((hsv[0] <= 10) || (hsv[0] >= 160)) { // 红色范围
                    ++redCount;
                }
            }
        }
    }

    // 打印调试信息
    std::cout << "图像总像素数: " << image.total() << std::endl;
    std::cout << "有效像素数 (validPixels): " << validPixels << std::endl;
    std::cout << "红色像素数 (redCount): " << redCount << std::endl;

/*
    // 有效像素比例不足时抛出异常
    if (validPixels < img.total() * 0.1) {
        throw std::runtime_error("图像有效颜色区域不足");
    }
*/
    // 计算红色像素比例
    float redRatio = static_cast<float>(redCount) / validPixels;
    std::string color = redRatio > redThreshold ? "red" : "black";

    std::cout << "红色像素比例 (redRatio): " << redRatio << std::endl;
    std::cout << "识别颜色: " << color << std::endl;
	return color;
}


ChessDatabase::ChessPiece extractChessPieceFeatures(
    const std::string& imagePath,
    double x,
    double y,
    const std::string& type)
{
    
	// 加载图像（彩色模式）
    cv::Mat img = cv::imread(imagePath, cv::IMREAD_COLOR);
    if (img.empty()) {
        throw std::runtime_error("无法加载图像: " + imagePath);
    }
// 调用封装后的各个特征的提取函数
	std::string color=extractcolor(img);
    std::vector<double> huMoments = extractHuMoments(img);
	std::vector<double> projHist=extractProjectionHistogram(img);
	std::array<double, 5> zoneDensity=extractZoneDensity(img);
	GeometricFeatures temporary=extractGeometricFeatures(img);
	std::cout<<"finish extractChessPieceFeatures"<<std::endl;

    // 构造棋子特征对象
    ChessDatabase::ChessPiece piece;
    piece.x = x;
    piece.y = y;
    piece.color = color; 
    piece.type = type;
	piece.area=temporary.area;
	piece.perimeter=temporary.perimeter;
	piece.aspectRatio=temporary.perimeter;
	piece.projHist=projHist;
	piece.zoneDensity=zoneDensity;

// 将提取的Hu矩复制到结构体中
    for (int i = 0; i < 7; ++i) {
        piece.huMoments[i] = huMoments[i];
    }
	
    return piece;
}












//多态特征提取，这个可以输入图像也可以（输入mat不是path）
ChessDatabase::ChessPiece extractChessPieceFeatures(
    cv::Mat img,
    double x,
    double y,
    const std::string& type)
{
    
// 调用封装后的各个特征的提取函数
    std::vector<double> huMoments = extractHuMoments(img);
    std::string color=extractcolor(img);
	std::vector<double> projHist=extractProjectionHistogram(img);
	std::array<double, 5> zoneDensity=extractZoneDensity(img);
	GeometricFeatures temporary=extractGeometricFeatures(img);
	

    // 构造棋子特征对象
    ChessDatabase::ChessPiece piece;
    piece.x = x;
    piece.y = y;
    piece.color = color; // 自动识别的颜色
    piece.type = type;
	piece.area=temporary.area;
	piece.perimeter=temporary.perimeter;
	piece.aspectRatio=temporary.perimeter;
	piece.projHist=projHist;
	piece.zoneDensity=zoneDensity;

// 将提取的Hu矩复制到结构体中
    for (int i = 0; i < 7; ++i) {
        piece.huMoments[i] = huMoments[i];
    }
	
    return piece;
}
